package com.tomato.lock.common;

import lombok.AllArgsConstructor;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.text.MessageFormat.format;

/**
 * tryLock()
 * tryLock(long time, TimeUnit unit)
 * <pre>
 *     1. 该方法为尝试获取锁，立即返回结果不会阻塞，如果获取到了返回true,获取不到返回false
 *     2. 该方法会还可以设置时间，如果在规定的时间没有获取到锁，则返回false，不会一直去获取锁
 *     3. 相比较lock方法，这个方法更加灵活，程序可以根据获取到锁的结果自由决定后续行为
 *     4. 使用该方法可以去避免死锁结果
 * </pre>
 *
 * <pre>
 *     tryLock()
 *     tryLock(long time, TimeUnit unit)
 *     第一个方法是获取锁，获取不到理解返回结果
 *     第二个方法可以传入时间,在规定时间内如果没有获取到锁就直接放弃了
 *     值得注意的是
 *     第一个方法是不会抛出异常的
 *     第二个方法会抛出InterruptedException,这是因为在获取锁的时间内很有可能被打断，因此会抛出异常
 *  </pre>
 * 这里写入一个死锁程序，通过tryLock就可以完全避免
 */
@AllArgsConstructor
public class TryLockDeadTest implements Runnable {
    static final Lock lock1 = new ReentrantLock();
    static final Lock lock2 = new ReentrantLock();
    boolean flag;

    public static void main(String[] args) {
        Thread t1 = new Thread(new TryLockDeadTest(true), "tomato-thread-1");
        Thread t2 = new Thread(new TryLockDeadTest(false), "tomato-thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        try {
            // flag 为 true,则先获取锁1然后在锁1里面获取锁2
            if (flag) {
                if (lock1.tryLock()) {
                    try {
                        System.out.println(format("{0}:获取到了lock1锁,开始执行任务", Thread.currentThread().getName()));
                        // 模拟耗时操作，这里休眠1s
                        Thread.sleep(1000);
                        if (lock2.tryLock()) {
                            try {
                                System.out.println(format("{0}:获取到lock2锁{1}", Thread.currentThread().getName(), "成功,开始执行任务"));
                                Thread.sleep(100);
                                System.out.println(format("{0}:获取到lock2锁{1}", Thread.currentThread().getName(), "成功,执行任务完成"));
                            } finally {
                                lock2.unlock();
                            }
                        } else {
                            System.out.println(format("{0}:获取到lock2锁{1}", Thread.currentThread().getName(), "失败"));
                        }
                    } finally {
                        // 注意： 只有获取到了锁才能释放
                        /*
                         *  写法格式为
                         *  if(lock.tryLock()) {
                         *      try{} finally { lock.unlock()}
                         *  } else {}
                         *
                         */
                        lock1.unlock();
                    }
                } else {
                    System.out.println(format("{0}:获取到了lock1锁失败", Thread.currentThread().getName()));
                }
            } else {
                if (lock2.tryLock()) {
                    try {
                        System.out.println(format("{0}:获取到了lock2锁,开始执行任务", Thread.currentThread().getName()));
                        // 模拟耗时操作，这里休眠1s
                        Thread.sleep(1000);
                        if (lock1.tryLock()) {
                            try {
                                System.out.println(format("{0}:获取到lock1锁,开始执行任务", Thread.currentThread().getName()));
                                Thread.sleep(100);
                                System.out.println(format("{0}:获取到lock1锁执行任务完成", Thread.currentThread().getName()));
                            } finally {
                                lock1.unlock();
                            }
                        } else {
                            System.out.println(format("{0}:获取到lock1锁失败", Thread.currentThread().getName()));
                        }
                    } finally {
                        // 注意： 只有获取到了锁才能释放
                        /*
                         *  写法格式为
                         *  if(lock.tryLock()) {
                         *      try{} finally { lock.unlock()}
                         *  } else {}
                         *
                         */
                        lock2.unlock();
                    }
                } else {
                    System.out.println(format("{0}:获取到了lock1锁失败", Thread.currentThread().getName()));
                }
            }
        } catch (InterruptedException e) {
            System.out.println("发生了中断: " + e.getMessage());
        }


    }
}
